package com.weichen.studentgameexchange.game.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.Db;
import com.weichen.studentgameexchange.common.common.Result;
import com.weichen.studentgameexchange.common.exception.ServiceException;
import com.weichen.studentgameexchange.game.dao.DeveloperMapper;
import com.weichen.studentgameexchange.game.entity.Developer;
import com.weichen.studentgameexchange.game.entity.Game;
import com.weichen.studentgameexchange.game.entity.GameDeveloper;
import com.weichen.studentgameexchange.game.service.IDeveloperService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author 惟尘
 * @since 2025-02-01
 */
@Service
public class DeveloperServiceImpl extends ServiceImpl<DeveloperMapper, Developer> implements IDeveloperService {

    @Autowired
    DeveloperMapper developerMapper;

    /**
     * 新增开发商
     *
     * @param developer
     */
    @Override
    public Result adminAdd(Developer developer) {
        Developer one = Db.lambdaQuery(Developer.class)
                .eq(developer.getDeveloperName()!=null,Developer::getDeveloperName, developer.getDeveloperName())
                .one();
        if (one == null) {
            developerMapper.insert(developer);
        } else
            return Result.error("开发商已存在！");
        return Result.success();
    }

    /**
     * 分页查找开发商信息
     *
     * @param keyword
     * @param page
     * @param size
     * @return
     */
    @Override
    public Result adminPage(String keyword, Integer page, Integer size) {
        // 1. 构建分页对象和基础查询条件
        Page<Developer> developerPage = new Page<>(page, size);
        LambdaQueryWrapper<Developer> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        // 2. 添加开发商名称模糊查询条件
        lambdaQueryWrapper.orderByDesc(Developer::getDeveloperId)
                .like(keyword != null, Developer::getDeveloperName, keyword);
        // 3. 执行分页查询
        Page<Developer> selectPage = developerMapper.selectPage(developerPage, lambdaQueryWrapper);
        List<Developer> developers = selectPage.getRecords();
        if (developers == null)
            return Result.success("开发商为空!");
        // 4. 批量加载多对多关系数据
        // --- 4.1 获取所有开发商ID ---
        List<Long> developerIds = developers
                .stream()
                .map(Developer::getDeveloperId)
                .toList();
        // --- 4.2 批量查询中间表 GameDeveloper ---
        List<GameDeveloper> gameDevelopers = Db.lambdaQuery(GameDeveloper.class)
                .in(GameDeveloper::getDeveloperId, developerIds)
                .list();
        // --- 4.3 提取所有关联的 gameId ---
        List<Long> gameIds = Db.lambdaQuery(GameDeveloper.class)
                .in(GameDeveloper::getDeveloperId, developerIds)
                .list()
                .stream()
                .map(GameDeveloper::getGameId)
                .distinct()//去重
                .toList();
        if (gameIds.size() == 0)
            return Result.success(selectPage);
        // --- 4.4 批量查询游戏名称 ---
        Map<Long, String> gameIdtoName = Db.lambdaQuery(Game.class)
                .in(Game::getGameId, gameIds)
                .list()
                .stream()
                .collect(Collectors.toMap(
                        Game::getGameId,
                        Game::getGameName,
                        (oldVal, newVal) -> oldVal // 去重
                ));
        // --- 4.5 构建开发商ID到游戏名称列表的映射 ---
        Map<Long, List<String>> developerGame = new HashMap<>();
        gameDevelopers.forEach(gd -> {
            Long developerId = gd.getDeveloperId();
            String gameName = gameIdtoName.getOrDefault(gd.getGameId(), "未知游戏");
            developerGame.computeIfAbsent(developerId, k -> new ArrayList<>()).add(gameName);
        });
        // 5. 填充游戏名称到 Developer 对象
        developers.forEach(developer -> {
            List<String> gameNames = developerGame.getOrDefault(developer.getDeveloperId(), new ArrayList<>());
            if (gameNames.isEmpty()) {
                developer.setGameName("无对应的游戏");
            } else {
                developer.setGameName(String.join("、", gameNames)); // 多游戏用顿号分隔
            }
        });
        return Result.success(selectPage);
    }

    /**
     * 查看单个开发商信息
     *
     * @param developerId
     */
    @Override
    public Developer adminSelectOne(Long developerId) {
        //1.通过developerId可以找到开发商对象
        Developer developer = developerMapper.selectById(developerId);
        if (StrUtil.isBlankIfStr(developer))
            return developer;
        //2.通过developerId可以在游戏开发商表找到对应的游戏id
        List<Long> gameIds = Db.lambdaQuery(GameDeveloper.class)
                .eq(GameDeveloper::getDeveloperId, developerId)
                .list()
                .stream()
                .map(GameDeveloper::getGameId)
                .distinct()
                .toList();
        //3.通过gameIds可以在游戏表中找到对应的游戏名
        if (gameIds.size() != 0) {
            List<String> gameNames = Db.lambdaQuery(Game.class)
                    .in(Game::getGameId, gameIds)
                    .list()
                    .stream()
                    .map(Game::getGameName)
                    .toList();
            developer.setGameName(String.join("、", gameNames));
        } else
            developer.setGameName("无对应的游戏");
        return developer;
    }

    /**
     * 修改单个开发商信息
     *
     * @param developer
     */
    @Override
    @Transactional // 确保操作原子性
    public Result adminUpdate(Developer developer) {
        //重复开发商名
        Long id = Db.lambdaQuery(Developer.class)
                .eq(developer.getDeveloperName() != null, Developer::getDeveloperName, developer.getDeveloperName())
                .one().getDeveloperId();
        if (!StrUtil.isBlankIfStr(id) && !id.equals(developer.getDeveloperId()) )
            return Result.error("开发商名重复，请重新输入！");
        // 1. 更新开发商基础信息,可能修改了开发商姓名
        Db.updateById(developer);
        //2.可能修改了对应的游戏
        Long developerId = developer.getDeveloperId();
        if (StrUtil.isBlankIfStr(developerId))
            throw new ServiceException("400","开发商Id不能为空！");
        //----2.1 将（‘、’）分隔的游戏名重新变成list----
        List<String> gameNames = StrUtil.isBlankIfStr(developer.getGameName()) ? new ArrayList<>() : Arrays.asList(developer.getGameName().split("、"));
        //----2.2 根据游戏名称查询游戏ID----
        List<Long> gameIds = new ArrayList<>();
        for (String gameName : gameNames) {
            Game game = Db.lambdaQuery(Game.class)
                    .eq(Game::getGameName, gameName)
                    .one();
            if (game == null)
                return Result.error("游戏不存在！请添加游戏：" + gameName + "<----");
            gameIds.add(game.getGameId());
        }
        //----2.3 删除旧的关联关系----
        Db.lambdaUpdate(GameDeveloper.class)
                .eq(GameDeveloper::getDeveloperId, developerId)
                .remove();
        //----2.4 插入新的关联关系----
        List<GameDeveloper> gameDeveloperList = gameIds.stream().map(gameId -> {
            return new GameDeveloper(gameId, developerId);
        }).toList();
        Db.saveBatch(gameDeveloperList);
        return Result.success();
    }

    /**
     * 删除单个开发商
     *
     * @param developerId
     */
    @Override
    public void adminDeleteOne(Long developerId) {
        if (developerId == null)
            throw new ServiceException("400","开发商Id不能为空！");
        List<Long> gameIds = Db.lambdaQuery(GameDeveloper.class)
                .eq(GameDeveloper::getDeveloperId, developerId)
                .list()
                .stream()
                .map(GameDeveloper::getGameId)
                .toList();
        if (gameIds.size()>0){
            gameIds.forEach(gameId -> {
                Db.lambdaUpdate(GameDeveloper.class)
                        .eq(GameDeveloper::getGameId, gameId)
                        .eq(GameDeveloper::getDeveloperId, developerId)
                        .remove();
            });
        }
        Db.lambdaUpdate(Developer.class)
                .eq(Developer::getDeveloperId, developerId)
                .remove();
    }


}
